controller_jerarquia_spaces = function(){
	
	var _this = this;
	var _modelo = null; //mantiene la jerarquia de spaces (organizada en edificios, pisos, spaces ...)
	var _3dObjectBuilder = null; //es el encargado de actualizar las propiedades/estilos de html/dom
					   //es el encargado de mantener la representacion visual de los spaces
	
	var _UI_jerarquia = new UI_panel_jerarquia(this);//inicializa el panel del 'arbolito' (TAB Jerarquia) 
	this.changeTreeTheme = function(){ _UI_jerarquia.getJsTree();}; //cambia el estilo del jsTree
	
	
	var _treeData = null; //contiene el arbol que viene del servidor (aulas.txt)
	var _nombreSpaces = null;


	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- SET TREE DATA --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//este es el punto de entrada!!
	//cuando lleguen la info del servidor (aulas.txt), se dispara la carga de los pisos
	//obs: el ajax que busca aulas.txt esta en CONTROLLER_CONTROL_FLOW
	this.setTreeData = function(data, nombreSpaces){
		_treeData = data; 
		_nombreSpaces = nombreSpaces;
		_this.init();//empiezo a cargar los pisos iniciales (init_config_file)
	};
	
	//MISC
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- GET LEVEL NAME --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.getLevelName = function(nombreEdificio, nombrePiso){
		for (var i = 0, l = _treeData.pisos.length; i<l; i++){
			if(_treeData.pisos[i].name == nombrePiso){
				return _treeData.pisos[i].nivel;
			}
		}
	}
	
	
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- INIT --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//funcion de inicializacion
	this.init = function(){
		_modelo = new modelo_jerarquia_spaces(this);
		 
		 $("#canvas_webgl").trigger('resize');//BUG (no toma el evento resize el domContainer de webgl)
		//la implementacion de este metodo en IU_panel_jerarquia, genera el arbol HTML con el que 
		 //el usuario tendra acceso a los spaces, clickeando encima de ellos
		_UI_jerarquia.generateHTMLTree(_treeData);
		_UI_jerarquia.setAutocomplete(_nombreSpaces);
		 						  
		_this.insertarNiveles(CONSTANTS.EDIFICIO, CONSTANTS.NIVELES_INICIALES);//TODO se asume 1 solo edificio
	};
	
	
	//DEPRECATED: ahora usar insertar niveles con un arreglo de niveles a insertar
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- INSERTAR NIVEL --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//callbefore = bool!! (ver codigo)
	//esta funcion se creo para mergear todos los pisos de un mismo nivel
	this.insertarNivel = function(nombreEdificio, nombreNivel,callback){
		
		var callbackExtended = function(){
			if (callback) callback();
			CONTROLLER_PAGE_STATE.finCreacionPisos3D();
		};
			
		var autoCallback = (callback)? callback : callbackExtended; 
		
		 var floorsToInsert = this.getUnloadedFloors(nombreEdificio, nombreNivel);
		 insertarNuevosPisos(floorsToInsert, autoCallback);
	};
	
	
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- INSERTAR NIVELES --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//callbefore = bool!! (ver codigo)
	//esta funcion se creo para mergear todos los pisos de un mismo nivel
	this.insertarNiveles = function(nombreEdificio, unloadedLevels,callback){
				
		CONTROLLER_PAGE_STATE.cargandoPisos();
		var callbackExtended = function(){
			if(callback) callback(); 
			CONTROLLER_PAGE_STATE.finCreacionPisos3D();
		}
		
		
		//creo una secuencia asincronica, que al terminar de cargar los pisos, llame a newCallBack
		var asyncSeqLevels = new UTILS.AsyncSequence({'total' : unloadedLevels.length, 'callback' : callbackExtended});
		//CONTROLLER_PAGE_STATE.cargandoPisos();
		
		 for (var i = 0, l = unloadedLevels.length; i< l; i++){
			 
			 var callbackPisos = function(){asyncSeqLevels.finishedItem();};
			 
			 var floorsToInsert = this.getUnloadedFloors(nombreEdificio, unloadedLevels[i]);
			 insertarNuevosPisos(floorsToInsert, callbackPisos);
			
		};				
	};
	

	var firstInsertion = true;
	
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- INSERTAR NUEVOS PISOS --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	function insertarNuevosPisos(pisos, callback){ //TODO: esto esta cableado para un solo EDIFICIO!
    	CONTROLLER_PAGE_STATE.cargandoPisos();
		
		var floorsToInsert = pisos;
		var buildingName = CONSTANTS.EDIFICIO;
		var urlFloors = CONSTANTS.PATH_JSONS+CONSTANTS.PATH_EDIFICIO; //TODO: suponiendo que todos los pisos son de un mismo edificio
		
		//a la funcion de callback, le agrego el resto de las funciones necesarias (extiendo)
		var newCallBack = function(){
			
			if (firstInsertion){
				  var buildingName = CONSTANTS.EDIFICIO; //ver si puedo usar la var de contexto
				  var nivel = _modelo.getRandomLevel(buildingName);//retorna un numero que representa el nivel
				  
				  if (nivel != null){
					  WEBGL.setSceneWrapper(CONSTANTS.ESCENA_INICIAL);
					  //var obj = _this.showLevel(buildingName, nivel, true, true);
						//if (obj) ANIMATOR.reposicionarCamaraFromTree(BUILDING_TARGET_POSITION, obj.nivelesActuales , obj.nivelesAnteriores, false, "level",null, false);
					  firstInsertion = false;
				  }else{
					  alert("error en controller jerarquia");//TODO
				  }
			}
			
			 WEBGL.updateSceneWrapper();
			//_this.generateVisualRepresentations();
			if(callback) callback();
			
		};
		
	   //si no hay pisos que insertar, ejecutamos el callback y retornamos
		if (!floorsToInsert.length) {if(newCallBack) newCallBack(); return;}
		
		//creo una secuencia asincronica, que al terminar de cargar los pisos, llame a newCallBack
		var asyncSeq = new UTILS.AsyncSequence({'total' : floorsToInsert.length, 'callback' : newCallBack});
		CONTROLLER_PAGE_STATE.cargandoPisos();
		
		 for (var i = 0, l = floorsToInsert.length; i< l; i++){
			 
			 var piso = floorsToInsert[i];
			 if (!piso.match(".json")){ piso += ".json";}
			 
			//pedimos los mapas iniciales
			 $.ajax({
				 //async : false,
			     type: "GET",
			     url: urlFloors+"/"+piso,
			     dataType: 'json', //esto es para que ande la version release!!
			     success: function(data){
			         _modelo.insertarPisoDesdeArchivo(buildingName, data);
			         asyncSeq.finishedItem(); //cada vez que llega un piso, sumamos el contador de la 
			         						  //secuencia de pedidos AJAX
			     },
			     error : function(){alert('error insertando piso'); asyncSeq.finishedItem();}
			 }); 
		};
	   
	};
	
	
	
	

	
	
	
	//MISC
	function getObjects3D(){
		var wrapper = WEBGL.getSceneWrapper();
		if (!wrapper) return null; 
		return wrapper.objetos3D;
	}
	
	//muestra un dado nivel 
	//si (makeActiveLevel) se agrega a los niveles activos
	//si (makeUnique) ese nivel sera el unico activo (saca el resto de los niveles activos)
	this.showLevel = function(nombreEdificio, nombreNivel, makeActiveLevel, makeUnique){
		
		var nivelesActuales = [];//niveles a los que le setearemos la opacidad en 1
		var nivelesAnteriores = [];//niveles a los que le setearemos la opacidad en 0
		
		var _objetos3D = getObjects3D();
		if (_objetos3D == null) return;
		
		var idTargetNivel = ""+ nombreEdificio + nombreNivel;
		
		
		
		for (var idNivel in _objetos3D){
			if (idNivel == idTargetNivel){ //no queremos animar el nivel que ya se esta mostrando
				nivelesActuales.push(_objetos3D[idNivel]);
				if (makeActiveLevel){
					if (makeUnique){
						for (var idOldActiveLevel in WEBGL.getSceneWrapper().activeLevels){
							if (idOldActiveLevel != idTargetNivel ){
								WEBGL.getSceneWrapper().activeLevels[idOldActiveLevel].hideSprites();
								nivelesAnteriores.push(WEBGL.getSceneWrapper().activeLevels[idOldActiveLevel]);
							}
							
						}
						
						WEBGL.getSceneWrapper().activeLevels = {};
						WEBGL.getSceneWrapper().levelsShown = {};
					}
					WEBGL.getSceneWrapper().activeLevels[idTargetNivel] = _objetos3D[idTargetNivel];
					WEBGL.getSceneWrapper().levelsShown[idTargetNivel] = _objetos3D[idTargetNivel];
					
					nivelesActuales.push(_objetos3D[idTargetNivel]);
					_objetos3D[idTargetNivel].showSprites();
				}else{
					_objetos3D[idNivel].hideSprites();
				}
				break;
			}
		};
		
		return {nivelesActuales: nivelesActuales , nivelesAnteriores : nivelesAnteriores};
	};
	
	//muestra los niveles de un edificio 
	//si (makeActiveLevels) se agrega a los niveles activos
	//si (makeUnique) ese nivel sera el unico activo (saca el resto de los niveles activos)
	this.showBuilding = function(nombreEdificio, makeActiveLevels/*, makeUnique*/){
		
		var nivelesActuales = [];//niveles a los que le setearemos la opacidad en 1
		var nivelesAnteriores = [];//niveles a los que le setearemos la opacidad en 0
		
		var _objetos3D = getObjects3D();//a futuro getObjects3D('nombreEdificio')
		if (_objetos3D == null) return;
		
		
		WEBGL.getSceneWrapper().levelsShown = {};
		for (var idNivel in _objetos3D){
			if (makeActiveLevels){
				WEBGL.getSceneWrapper().activeLevels[idNivel] = _objetos3D[idNivel];
				_objetos3D[idNivel].showSprites();
			}
			
			WEBGL.getSceneWrapper().levelsShown[idNivel] = _objetos3D[idNivel];
			nivelesActuales.push(_objetos3D[idNivel]);
		};
		
		return {nivelesActuales: nivelesActuales , nivelesAnteriores : nivelesAnteriores};
	};
	
	
	
	var _idsObjToRender = []; //para salir del paso
	var _objectsToRender = []; //mantiene la coleccion de ojectos que todavia no tienen una representacion visual
	var _interFloorPortalsToDelete = [];
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- GENERATE VISUAL REPRESENTATIONS --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//generea la representacion visual de los spaces, portales
	this.generateVisualRepresentations = function(wrapperScene){
		
		var insertedIds = wrapperScene.insertedIds;
		var toRender = [];
		for(var i = 0, l = _objectsToRender.length; i < l; i++){
			if (!insertedIds[_objectsToRender[i].IDJerarquia]){ //si no inserte en la escena un objeto con tal ID, lo inserto
				toRender.push(_objectsToRender[i]);
			}
		}
		
		console.log("_interFloorPortalsToDelete", _interFloorPortalsToDelete)
		for(var i = 0, l = _interFloorPortalsToDelete.length; i < l; i++){
			if (!wrapperScene.deletedDanglingIds[_interFloorPortalsToDelete[i]]){ //si no inserte en la escena un objeto con tal ID, lo inserto
				wrapperScene.deletePortal(_interFloorPortalsToDelete[i]);
			}
		}
		
		
		//esto pasarlo por parametro
		_3dObjectBuilder = wrapperScene.getObjectBuilder(); //new builderSceneObjects(_this, MESH_BUILDER);//TODO MESH_BUILDER es var global por ahora

		var objeto = null;
//		console.log('_objectsToRender',_objectsToRender)
		//console.log('toRender',toRender.length, toRender)
		for (var i = 0, l = toRender.length; i < l; i++){
			
			objeto = toRender[i];
			
			if (objeto.clase == "nivel"){
				
				var nivel = _3dObjectBuilder.generateLevelRepresentation(objeto);//no hace casi nada (por ahora. dsp tiene previsto generar todo los pisos que componen un nivel, mergeados)
				wrapperScene.addLevel(objeto.buildingName, objeto.indice, nivel, toRender[i].IDJerarquia);
				UTILS.setOpacity(nivel, 0);
			
				if (nivel.TFCwalls){
					wrapperScene.addObjectToScene(nivel.TFCwalls);
				}
				
			}else if (objeto.clase == "inter_floor") {//TODO
				
				if (objeto.dangling){
					//TODO solo duplicar si el portal conecta pisos de distintos niveles
					var mesh = _3dObjectBuilder.generateInterFloorPortal(objeto, "source");//				
					wrapperScene.addInterFloorDanglingPortal(objeto.sourceSpace.piso.buildingName, objeto.sourceSpace.piso.level, mesh, toRender[i].IDJerarquia, objeto.id);
					UTILS.setOpacity(mesh, 0);
				}else{
					
					//TODO solo duplicar si el portal conecta pisos de distintos niveles
					var meshSource = _3dObjectBuilder.generateInterFloorPortal(objeto, "source");//	
					var meshTarget = _3dObjectBuilder.generateInterFloorPortal(objeto, "target");//	
					meshSource.doubleSided = true;
					meshTarget.doubleSided = true;
					
					UTILS.setOpacity(meshSource, 1);
					UTILS.setOpacity(meshTarget, 1);
					
					var params = {};
					params.sourceBuildingName = objeto.sourceSpace.piso.buildingName;
					params.sourceLevel = objeto.sourceSpace.piso.level;
					params.meshSource = meshSource;
					params.idInterno = toRender[i].IDJerarquia;
					params.idModeloPortal = objeto.id;
					params.targetBuildingName = objeto.targetSpace.piso.buildingName;
					params.targetLevel = objeto.targetSpace.piso.level;
					params.meshSource = meshTarget;
					
					wrapperScene.addInterFloorPortal(params);
					
					_interFloorPortalsToDelete.push(objeto.id);
				}
				
				
				
				
				
				
				
				
			}
			
			
			if (WEBGL.getSceneWrapper().levelsShown == null){	
				WEBGL.getSceneWrapper().levelsShown = {};
				WEBGL.getSceneWrapper().activeLevels = {};
				 var obj = _this.showLevel(objeto.buildingName, objeto.indice, true, true);
				 if (obj) ANIMATOR.reposicionarCamaraFromTree(BUILDING_TARGET_POSITION, obj.nivelesActuales , [], false, "level",null, false);
			}
		};
		
		toRender = null;
		toRender = [];
	};
	
	
	//TODO TODO TODO TODO TODO TODO TODO 
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- GET ACTIVE LEVEL INDEX --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.getActiveLevelHeight = function(){
		var sum = 0;
		for (var id in WEBGL.getSceneWrapper().activeLevels){
			sum += Number(WEBGL.getSceneWrapper().activeLevels[id].TFCid);
		}
		return sum*100;
	};
	
	//TODO
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- IS ACTIVE LEVEL --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//determina si el nivel de un piso esta activo (o sea, con opacidad en 1)
	this.isActiveLevel = function(nombreEdificio, nombreNivel){
		for (var id in WEBGL.getSceneWrapper().activeLevels){
			idd = ""+nombreEdificio+ nombreNivel;
			if (id == idd){
				return true;
			}
		}
	};
	
	
	var idGen = 0;
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- PUSH OBJECT --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//maneja la coleccion de objetos para generar la representacion visual
	this.pushObject = function(objeto){
		objeto.IDJerarquia = idGen;
		_idsObjToRender.push(idGen++);
		
		if (objeto.clase == 'nivel'){
			_objectsToRender.unshift(objeto);//agrego adelante
		}else{
			_objectsToRender.push(objeto);
		}
		
		
	};
	
	
		
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- EXISTE PISO --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.existePiso = function(nombreEdificio, nombrePiso){
		return _modelo.existePiso(nombreEdificio, nombrePiso);
	};
	
	
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- GET UNLOADED FLOORS --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.getUnloadedFloors = function(nombreEdificio, nombreNivel){
		var arr = [];
		if ( nombreEdificio != _treeData.nombre) {alert('CONTROLLER_JERARQUIA_SPACES. (1.1) error en el nombre del edificio'); return;}
		if ( !_treeData.niveles[nombreNivel] || !_treeData.niveles[nombreNivel].pisos) {alert('CONTROLLER_JERARQUIA_SPACES. (1.2) error nombre nivel'); return;}
		
		var pisos = _treeData.pisos;//(COD 9_4_12)
		var pisosEnNivel = _treeData.niveles[nombreNivel].pisos;
		var piso = null;
		//console.log("tree dta", _treeData);
		
		for (var i = 0, l = pisosEnNivel.length ; i<l; i++){
			piso = pisos[pisosEnNivel[i]];
			if (!_modelo.existePiso(nombreEdificio, piso.name)){
				arr.push(piso.name);
			}
		};
		return arr;
	};
	
	
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- GET UNLOADED LEVELS --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.getUnloadedLevels = function(nombreEdificio){
		var arr = []; 
		if ( nombreEdificio != _treeData.nombre) {alert('CONTROLLER_JERARQUIA_SPACES. (2) error en el nombre del edificio'); return;}
		
		for (var idNivel in _treeData.niveles){
			if (!_modelo.existeNivel(nombreEdificio, idNivel)){
				arr.push(idNivel);
			}
		}
		
		return arr;
	};
	
	
	
	
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- GET PORTAL ID --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//retorna el id del portal interno que conecta 2 spaces
	//si no se encuentra el portal, retorna null
	this.getPortalID = function(nombreEdificio, nombrePiso, sourceSpaceName, targetSpaceName){
		return _modelo.getPortalIntraSpacesID(nombreEdificio, nombrePiso, sourceSpaceName, targetSpaceName);
	};
	
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- GET PORTAL 3D --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	//retorna el objeto 3D que representa al portal (solo los de tipo escalera, por ahora)
	this.getPortal3D = function(nombreEdificio, nombrePiso, portalID){
		//console.log("donde falla",nombreEdificio, nombrePiso, portalID );
		return _objetos3D.pisos[""+nombreEdificio+nombrePiso].TFCescalerasByID[portalID];
//		return _portales[portalID];
	};

	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- GET SPACE CENTROID --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.getSpaceCentroid = function(nombreEdificio, nombrePiso, nombreSpace){
		var space = _modelo.getSpace(nombreEdificio, nombrePiso, nombreSpace);
		if (!space) return null;
		
		return space.contour.centroid;
	};
	
	
	//TODO (no devolver el objeto!!!)
	this.getSpace = function(nombreEdificio, nombrePiso, nombreSpace){
		var space = _modelo.getSpace(nombreEdificio, nombrePiso, nombreSpace);
		if (!space) return null;
		
		return space;
	};
	
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- GET FLOOR CENTROID --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.getFloorCentroid = function(nombreEdificio, nombrePiso){
		var floor = _modelo.getFloor(nombreEdificio, nombrePiso);
		if (!floor) return null;
		
		return floor.contour.centroid;
	};
	
	
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- GET LEVEL CENTROID --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.getLevelCentroid = function(nombreEdificio, nombreNivel){
		return BUILDING_TARGET_POSITION;//TODO
		
		var floors = _modelo.getFloorsFromLevel(nombreEdificio, nombreNivel);
		if (!floors) return null;
		
		var x = 0, y = 0, z = 0;
		var l = floors.length;
		for (var i = 0; i < l; i++){
			x += floors[i].contour.centroid.x;
			z += floors[i].contour.centroid.z;
		}
		if (l){
			x /= l;
			z /= l;
		}
		
		return {x: x, y: y, z: z};
	};
	
	
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- GET SPRITE --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.getSprite = function(nombreEdificio, nombreNivel, nombrePiso, idSpace){
		var _objetos3D = getObjects3D();
		if (_objetos3D == null) return;

		var id = ""+nombreEdificio + nombreNivel;
		var nivel = _objetos3D[id];
		if (nivel)	//si existe el nivel	
		{
			var piso = nivel.TFCpisos[nombrePiso];
			if (piso && piso.TFCspritesBySpace[idSpace]){//si existe el piso y un space con idSpace
				return piso.TFCspritesBySpace[idSpace];//retorno el space
			}
		}
		console.log('error', nombreEdificio, nombreNivel, nombrePiso, idSpace)
		alert('error');
		return null;		
	};
	
	//---------------------------------------------------------------------------------------------------------------------
	//----------------------------------- GET TEXT XY --------------------------------------------
	//---------------------------------------------------------------------------------------------------------------------
	this.getTextXY = function(ray){
		
		var _objetos3D = getObjects3D();
		if (_objetos3D == null) return;
		
		for (var id in WEBGL.getSceneWrapper().activeLevels){
			
			var spritesDelNivel = [];
		       var sprite;
			
			//var id= ""+_activeBuilding + WEBGL.getSceneWrapper().activeLevels[id].TFCid;
		     var nivel = _objetos3D[id];
		     
			for (var nombrePiso in nivel.TFCpisos){
		    	   spritesDelNivel = nivel.TFCpisos[nombrePiso].TFCsprites;
		    	   for (var j = 0, k = spritesDelNivel.length; j <k; j++){
		               sprite = spritesDelNivel[j];
		               
		               var inters = UTILS.intersectsSprite(sprite, ray, 16); 
		               if (inters[0] != null){
		            	   return sprite;
		                }
		            }
		        } 
		}
	  } ;     

		
		var lastFloor = null;
		
		//---------------------------------------------------------------------------------------------------------------------
		//----------------------------------- SHOW BUILDING --------------------------------------------
		//---------------------------------------------------------------------------------------------------------------------
		this.selectBuilding = function(nombreEdificio){
			
			
			var callback = function(){
				var centroid = _this.getLevelCentroid(nombreEdificio);
//					var centroid = CONTROLLER_JERARQUIA_SPACES.getSpaceCentroid(nombreEdificio, nombrePiso, nombreSpace);
				
				if(!centroid) {	alert("ERROR. en centroid es null");return;}
				
				params = {};
				params.type = 'tree_select_building';
				params.climbY = false;
				params.centroid = centroid;
				params.nombreEdificio = nombreEdificio;
				WEBGL.activeWrapper().handleEvent(params);
			};
			
			var unloadedLevels = _this.getUnloadedLevels(nombreEdificio);//retorna una lista de los nombres de pisos q faltan cargar para un dado nivel
			if (unloadedLevels && unloadedLevels.length){
				var callbackExpand = function(){
					callback();
					CONTROLLER_PAGE_STATE.finCreacionPisos3D();
				}
				_this.insertarNiveles(nombreEdificio, unloadedLevels ,callbackExpand);//TODO se asume 1 solo edificio
			}else{callback();}
			
			lastFloor = null; //TODO var global
		};
		
		
		this.loadLevel = function(nombreEdificio, nombreNivel, callback){
			var unloadedFloors = _this.getUnloadedFloors(nombreEdificio, nombreNivel);//retorna una lista de los nombres de pisos q faltan cargar para un dado nivel
			if (unloadedFloors && unloadedFloors.length){
//				CONTROLLER_JERARQUIA_SPACES.insertarNuevosPisos(unloadedFloors,callback);//TODO se asume 1 solo edificio
				
				var callbackExpand = function(){
					callback();
					CONTROLLER_PAGE_STATE.finCreacionPisos3D();
				}
				
				_this.insertarNivel(nombreEdificio, nombreNivel, callbackExpand);//TODO se asume 1 solo edificio
				
			}else{
				console.log('EN NIVEL --> no tengo que cargar pisos');
				callback();
			}
		};
		
		//---------------------------------------------------------------------------------------------------------------------
		//----------------------------------- SHOW LEVEL --------------------------------------------
		//---------------------------------------------------------------------------------------------------------------------
		this.selectLevel = function(nombreEdificio, nombreNivel){ 
//console.log("nombreEdificio, nombreNivel",nombreEdificio, nombreNivel)
			var callback = function(){
				var centroid = _this.getLevelCentroid(nombreEdificio, nombreNivel);
				
				if(!centroid) {	alert("ERROR. centroid es null"); return;}

				params = {};
				params.type = 'tree_select_level';
				params.climbY = false;
				params.centroid = centroid;
				params.nombreEdificio = nombreEdificio;
				params.nombreNivel = nombreNivel;
				WEBGL.activeWrapper().handleEvent(params);
			};
			
			_this.loadLevel(nombreEdificio, nombreNivel, callback);
			
			lastFloor = null; //TODO var global
		};
		
		
		//---------------------------------------------------------------------------------------------------------------------
		//----------------------------------- SHOW FLOOR --------------------------------------------
		//---------------------------------------------------------------------------------------------------------------------
		this.selectFloor = function(nombreEdificio, nombreNivel, nombrePiso){
			
			var climbY = (nombrePiso != lastFloor); //bool
			var callback = function(){
				var centroid = CONTROLLER_JERARQUIA_SPACES.getFloorCentroid(nombreEdificio, nombrePiso);
//				var centroid = CONTROLLER_JERARQUIA_SPACES.getSpaceCentroid(nombreEdificio, nombrePiso, nombreSpace);
				
				if(!centroid) { alert("ERROR. en UI_panel_jerarquia. centroid es null"); return;}
				
				params = {};
				params.type = 'tree_select_floor';
				params.climbY = climbY;
				params.centroid = centroid;
				params.nombreEdificio = nombreEdificio;
				params.nombreNivel = nombreNivel;
				params.nombrePiso = nombrePiso;
				WEBGL.activeWrapper().handleEvent(params);
			};
			
			var bool = _this.existePiso(nombreEdificio, nombrePiso);
			if (!bool){
				
				var callbackExpand = function(){
					callback();
					CONTROLLER_PAGE_STATE.finCreacionPisos3D();
				}
				
				//CONTROLLER_JERARQUIA_SPACES.insertarNuevosPisos([nombrePiso],callback);//TODO se asume 1 solo edificio
				_this.insertarNivel(nombreEdificio, nombreNivel, callbackExpand );//TODO se asume 1 solo edificio
				
			}else{callback();}
			
			lastFloor = nombrePiso; //TODO var global
		};
		
		
		//---------------------------------------------------------------------------------------------------------------------
		//----------------------------------- SHOW SPACE --------------------------------------------
		//---------------------------------------------------------------------------------------------------------------------
		this.selectSpace = function(nombreEdificio, nombreNivel, nombrePiso, idSpace){
			var climbY = (nombrePiso != lastFloor); //bool
			var callback = function(){
				var centroid = _this.getSpaceCentroid(nombreEdificio, nombrePiso, idSpace);
				
				if(!centroid) {
					alert("ERROR. en UI_panel_jerarquia. centroid es null");
					return;
				}
				
				params = {};
				params.type = 'tree_select_space';
				params.climbY = climbY;
				params.centroid = centroid;
				params.nombreEdificio = nombreEdificio;
				params.nombreNivel = nombreNivel;
				params.nombrePiso = nombrePiso;
				params.idSpace = idSpace;
				WEBGL.activeWrapper().handleEvent(params);
				
				};//fin callback
			
				var bool = _this.existePiso(nombreEdificio, nombrePiso);
				if (!bool){
					
					var callbackExpand = function(){
						callback();
						CONTROLLER_PAGE_STATE.finCreacionPisos3D();
					}
					//CONTROLLER_JERARQUIA_SPACES.insertarNuevosPisos([nombrePiso],callback);//TODO se asume 1 solo edificio
					_this.insertarNivel(nombreEdificio, nombreNivel, callbackExpand);//TODO se asume 1 solo edificio
					
				}else{callback();}
				
				lastFloor = nombrePiso; //TODO var global
		};
		
		
		
		
		
		
	//TODO a futuro
	function changeVista(nuevaVista){
		//eliminar objetos 3d generados por la vista anterior (de la escena)
		//generar los objetos 3d para la vista actual (a la escena)
		
		//de esta forma podria modificar la representacion de los spaces,
		//por ej, con una vista los muestro opacos, y con otra transparentes y con brillo :P
	}
	
  
	
	
};